<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=545812

Test DOM full-screen API.

-->
<head>
  <title>Test for Bug 545812</title>
  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript" src="file_fullscreen-utils.js"></script>
  <style>
  body {
    background-color: black;
  }
  </style>
</head>
<body>
<script type="application/javascript">

/** Test for Bug 545812 **/

function ok(condition, msg) {
  opener.ok(condition, "[fullscreen] " + msg);
}

function is(a, b, msg) {
  opener.is(a, b, "[fullscreen] " + msg);
}

/*
<html>
  <body onload='document.body.requestFullscreen();'>
  <iframe id='inner-frame'></iframe>
  </body>
</html>
*/
var iframeContents = "data:text/html;charset=utf-8,<html><body onload%3D'parent.SimpleTest.waitForFocus(function(){document.body.requestFullscreen();});'><iframe id%3D'inner-frame'><%2Fiframe><%2Fbody><%2Fhtml>";

var iframe = null;
var outOfDocElement = null;
var inDocElement = null;
var container = null;
var button = null;


function sendMouseClick(element) {
  synthesizeMouseAtCenter(element, {});
}

function fullScreenElement() {
  return document.getElementById('full-screen-element');
}

function enter1(event) {
  is(event.target, document, "Event target should be full-screen document #1");
  ok(document.fullscreen, "Document should be in fullscreen");
  is(document.fullscreenElement, fullScreenElement(),
     "Full-screen element should be div element.");
  ok(document.fullscreenElement.matches(":fullscreen"),
     "FSE should match :fullscreen");
  var fse = fullScreenElement();
  addFullscreenChangeContinuation("exit", exit1);
  fse.parentNode.removeChild(fse);
  is(document.fullscreenElement, null,
     "Full-screen element should be null after removing.");
  document.body.appendChild(fse);
  is(document.fullscreenElement, null,
     "Full-screen element should still be null after re-adding former FSE.");
}

function exit1(event) {
  is(event.target, document, "Event target should be full-screen document #2");
  ok(!document.fullscreen, "Document should not be in fullscreen");
  is(document.fullscreenElement, null, "Full-screen element should be null.");
  iframe = document.createElement("iframe");
  iframe.allowFullscreen = true;
  addFullscreenChangeContinuation("enter", enter2);
  document.body.appendChild(iframe);
  iframe.src = iframeContents;
}

function enter2(event) {
  is(event.target, document, "Event target should be full-screen document #3");
  is(document.fullscreenElement, iframe,
     "Full-screen element should be iframe element.");
  is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body,
     "Full-screen element in subframe should be body");
  
  // The iframe's body is full-screen. Cancel full-screen in the subdocument to return
  // the full-screen element to the previous full-screen element. This causes
  // a fullscreenchange event.
  addFullscreenChangeContinuation("exit", exit2);
  document.exitFullscreen();
}

function exit2(event) {
  is(document.fullscreenElement, null,
     "Full-screen element should have rolled back.");
  is(iframe.contentDocument.fullscreenElement, null,
     "Full-screen element in subframe should be null");
  
  addFullscreenChangeContinuation("enter", enter3);
  fullScreenElement().requestFullscreen();
}

function enter3(event) {
  is(event.target, document, "Event target should be full-screen document #3");
  is(document.fullscreenElement, fullScreenElement(),
     "Full-screen element should be div.");
  
  // Transplant the FSE into subdoc. Should exit full-screen.
  addFullscreenChangeContinuation("exit", exit3);
  var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
  var fse = fullScreenElement();
  _innerFrame.contentDocument.body.appendChild(fse);
  is(document.fullscreenElement, null,
     "Full-screen element transplanted, should be null.");
  is(iframe.contentDocument.fullscreenElement, null,
     "Full-screen element in outer frame should be null.");
  is(_innerFrame.contentDocument.fullscreenElement, null,
     "Full-screen element in inner frame should be null.");
  
  document.body.appendChild(fse);
}

function exit3(event) {
  is(event.target, document, "Event target should be full-screen document #4");
  is(document.fullscreenElement, null, "Full-screen element should be null.");
  document.body.removeChild(iframe);
  iframe = null;

  // Do a request out of document. It should be denied.
  // Continue test in the following fullscreenerror handler.
  outOfDocElement = document.createElement("div");
  addFullscreenErrorContinuation(error1);    
  outOfDocElement.requestFullscreen();
}

function error1(event) {
  ok(!document.fullscreenElement,
     "Requests for full-screen from not-in-doc elements should fail.");
  container = document.createElement("div");
  inDocElement = document.createElement("div");
  container.appendChild(inDocElement);
  fullScreenElement().appendChild(container);

  addFullscreenChangeContinuation("enter", enter4);
  inDocElement.requestFullscreen();
}

function enter4(event) {
  is(event.target, document, "Event target should be full-screen document #5");
  is(document.fullscreenElement, inDocElement, "FSE should be inDocElement.");

  // Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
  addFullscreenChangeContinuation("exit", exit_to_arg_test_1);
  container.parentNode.removeChild(container);
  is(document.fullscreenElement, null,
     "Should not have a full-screen element again.");
}

function exit_to_arg_test_1(event) {
  ok(!document.fullscreenElement,
     "Should have left full-screen mode (third time).");
  addFullscreenChangeContinuation("enter", enter_from_arg_test_1);
  var threw = false;
  try {
    fullScreenElement().requestFullscreen(123);
  } catch (e) {
    threw = true;
    // trigger normal fullscreen so that we continue
    fullScreenElement().requestFullscreen();
  }
  ok(!threw, "requestFullscreen with bogus arg (123) shouldn't throw exception");
}

function enter_from_arg_test_1(event) {
  ok(document.fullscreenElement,
     "Should have entered full-screen after calling with bogus (ignored) argument (fourth time)");
  addFullscreenChangeContinuation("exit", exit_to_arg_test_2);
  document.exitFullscreen();
}

function exit_to_arg_test_2(event) {
  ok(!document.fullscreenElement,
     "Should have left full-screen mode (fourth time).");
  addFullscreenChangeContinuation("enter", enter_from_arg_test_2);
  var threw = false;
  try {
    fullScreenElement().requestFullscreen({ vrDisplay: null });
  } catch (e) {
    threw = true;
    // trigger normal fullscreen so that we continue
    fullScreenElement().requestFullscreen();
  }
  ok(!threw, "requestFullscreen with { vrDisplay: null } shouldn't throw exception");
}

function enter_from_arg_test_2(event) {
  ok(document.fullscreenElement,
     "Should have entered full-screen after calling with vrDisplay null argument (fifth time)");
  addFullscreenChangeContinuation("exit", exit4);
  document.exitFullscreen();
}

function exit4(event) {
  ok(!document.fullscreenElement,
     "Should be back in non-full-screen mode (fifth time)");
  SpecialPowers.pushPrefEnv({"set":[["full-screen-api.allow-trusted-requests-only", true]]}, function() {
    addFullscreenErrorContinuation(error2);
    fullScreenElement().requestFullscreen();
  });
}

function error2(event) {
  ok(!document.fullscreenElement,
     "Should still be in normal mode, because calling context isn't trusted.");
  button = document.createElement("button");
  button.onclick = function(){fullScreenElement().requestFullscreen();}
  fullScreenElement().appendChild(button);
  addFullscreenChangeContinuation("enter", enter5);
  sendMouseClick(button);
}

function enter5(event) {
  ok(document.fullscreenElement, "Moved to full-screen after mouse click");
  addFullscreenChangeContinuation("exit", exit5);
  document.exitFullscreen();
}

function exit5(event) {
  ok(!document.fullscreenElement,
     "Should have left full-screen mode (last time).");
  SpecialPowers.pushPrefEnv({
    "set":[["full-screen-api.allow-trusted-requests-only", false],
           ["full-screen-api.enabled", false]]}, function() {
              is(document.fullscreenEnabled, false, "document.fullscreenEnabled should be false if full-screen-api.enabled is false");
              addFullscreenErrorContinuation(error3);
              fullScreenElement().requestFullscreen();
  });
}

function error3(event) {
  ok(!document.fullscreenElement,
     "Should still be in normal mode, because pref is not enabled.");

  SpecialPowers.pushPrefEnv({"set":[["full-screen-api.enabled", true]]}, function() {
    is(document.fullscreenEnabled, true, "document.fullscreenEnabled should be true if full-screen-api.enabled is true");
    opener.nextTest();
  });
}

function begin() {
  testNamespaces(() => {
    addFullscreenChangeContinuation("enter", enter1);
    fullScreenElement().requestFullscreen();
  });
}

function testNamespaces(followupTestFn) {
  let tests = [
    {allowed: false, name: "element", ns: "http://www.w3.org/XML/1998/namespace"},
    {allowed: false, name: "element", ns: "http://www.w3.org/1999/xlink"},
    {allowed: false, name: "element", ns: "http://www.w3.org/2000/svg"},
    {allowed: false, name: "element", ns: "http://www.w3.org/1998/Math/MathML"},
    {allowed: false, name: "mathml",  ns: "unknown"},
    {allowed: false, name: "svg",     ns: "unknown"},
    {allowed: true,  name: "element", ns: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"},
    {allowed: true,  name: "element", ns: "http://www.w3.org/1999/xhtml"},
    {allowed: true,  name: "svg",     ns: "http://www.w3.org/1999/xhtml"},
    {allowed: true,  name: "math",    ns: "http://www.w3.org/1999/xhtml"},
    {allowed: true,  name: "svg",     ns: "http://www.w3.org/2000/svg"},
    {allowed: true,  name: "math",    ns: "http://www.w3.org/1998/Math/MathML"},
    {allowed: true,  name: "element"},
  ];

  function runNextNamespaceTest() {
    let test = tests.shift();
    if (!test) {
      followupTestFn();
      return;
    }

    let elem = test.ns ? document.createElementNS(test.ns, test.name) :
                         document.createElement(test.name);
    document.body.appendChild(elem);

    if (test.allowed) {
      addFullscreenChangeContinuation("enter", () => {
        ok(document.fullscreen, "Document should be in fullscreen");
        is(document.fullscreenElement, elem,
           `Element named '${test.name}' in this namespace should be allowed: ${test.ns}`);
        addFullscreenChangeContinuation("exit", runNextNamespaceTest);
        document.body.removeChild(elem);
      });
    } else {
      addFullscreenErrorContinuation(() => {
        ok(!document.fullscreenElement,
           `Element named '${test.name}' in this namespace should not be allowed: ${test.ns}`);
        document.body.removeChild(elem);
        runNextNamespaceTest();
      });
    }

    elem.requestFullscreen();
  }

  runNextNamespaceTest();
}
</script>
</pre>
<div id="full-screen-element"></div>
</body>
</html>
